----------------------------------
-- 角色DB相关逻辑
-- isNameExistInDB 		角色名是否存在
-- getDb 				根据uuid取角色信息（优先取内存）
-- getDbByName 			根据名字取角色信息（优先取内存）
-- getDbByAccount 		根据账号取角色信息（优先取内存）
-- loadRole 			根据账号取db
-- saveRole 			保存角色整个db
-- saveRoleSset 		仅对角色db某些字段进行修改
-- createDefaultRole 	初始化角色db信息
----------------------------------
local LuaMongo = _G.lua_mongo
local Config = require("Config")
local DB = require("common.DB")
local ObjHuman = require("core.ObjHuman")
local HeroDefine = require("hero.HeroDefine")
local CreateRole = require("role.CreateRole")
local CombatDefine = require("combat.CombatDefine")
local RoleLogic = require("role.RoleLogic")
local RoleHeadLogic = require("role.RoleHeadLogic")
local Util = require("common.Util")

local QueryByAccount = {}		--按帐号查询
local QueryByName = {}			--按角色名查询
local QueryByUuid = {}			--按uuid查询
local QueryByIdentity = {}		--按identity查询
local QueryUpdateChar = {}

local FieldName = {name = 1}
local FieldAccount = {account = 1}

local tempData = {}
function isNameExistInDB(name)
	QueryByName.name = name
	tempData.name = nil
	LuaMongo.find(DB.db_char, QueryByName, FieldName)
	return LuaMongo.next(tempData) and tempData
end

function isAccountExistInDB(account)
	QueryByAccount.account = account
	tempData.account = nil
	LuaMongo.find(DB.db_char, QueryByAccount, FieldAccount)
	return LuaMongo.next(tempData) and tempData
end

function isUuidExistInDB(uuid)
	QueryByUuid._id = uuid
	tempData.account = nil
	LuaMongo.find(DB.db_char, QueryByUuid, FieldAccount)
	return LuaMongo.next(tempData) and tempData
end

local f = {}
function getDb(uuid, fields)
	local t = ObjHuman.onlineUuid[uuid]
	if t then
		return t.db, t.fd ~= nil
	end
	QueryByUuid._id = uuid
	local data = {}
	if type(fields) == "string" then
		local k = next(f)
		if k then f[k] = nil end
		f[fields] = 1
		fields = f
	end
	LuaMongo.find(DB.db_char, QueryByUuid, fields)
	return LuaMongo.next(data) and data, nil
end

function getDbByName(name, fields)
	if not name then
		assert()
	end
	local t = ObjHuman.onlineHuman[name]
	if t then
		return t.db, t.fd ~= nil
	end
	QueryByName.name = name
	local data = {}
	if type(fields) == "string" then
		local k = next(f)
		if k then f[k] = nil end
		f[fields] = 1
		fields = f
	end
	LuaMongo.find(DB.db_char, QueryByName, fields)
	return LuaMongo.next(data) and data, nil
end

function getDbByNameRegex(name, fields)
	QueryByName.name = {["$regex"] = name}
	local data = {}
	if type(fields) == "string" then
		local k = next(f)
		if k then f[k] = nil end
		f[fields] = 1
		fields = f
	end
    RoleLogic.makeRoleBaseFields(fields)
	LuaMongo.find(DB.db_char, QueryByName, fields,50)
    local userList = {}
    local len = 0
    while true do
        local data = {}
        if not LuaMongo.next(data) then
			break
		end
        len = len + 1
        userList[len] = {}
        userList[len].name = data.name
        userList[len].uuid = data._id
        userList[len].account = data.account
        userList[len].identity = data.identity
        userList[len].lv = data.lv
        userList[len].head = data.head
        userList[len].headFrame = data.headFrame
        userList[len].unionUuid = data.unionUuid
        userList[len].blue = data.blue
        userList[len].yellow = data.yellow
        userList[len].zhandouli = data.zhandouli
    end
	return userList,#userList
end

function getDbByAccount(account, fields)
	local t = ObjHuman.onlineAccount[account]
	if t then
		return t.db, t.fd ~= nil
	end
	QueryByAccount.account = account
	local data = {}
	if type(fields) == "string" then
		local k = next(f)
		if k then f[k] = nil end
		f[fields] = 1
		fields = f
	end
	LuaMongo.find(DB.db_char, QueryByAccount, fields)
	return LuaMongo.next(data) and data, nil
end

function loadRole(account)
	QueryByAccount.account = account
	local data = {}
	LuaMongo.find(DB.db_char, QueryByAccount)
	if LuaMongo.next(data) then
		return data
	end
end

function getDbByIdentity(identity,fields)
	QueryByIdentity.identity = identity
	local data = {}
	if type(fields) == "string" then
		local k = next(f)
		if k then f[k] = nil end
		f[fields] = 1
		fields = f
	end
	LuaMongo.find(DB.db_char, QueryByIdentity, fields)
	return LuaMongo.next(data) and data, nil
end


function saveRole(db)
	QueryUpdateChar._id = db._id
	LuaMongo.update(DB.db_char, QueryUpdateChar, db)
end

local tempTb = {}
function saveRoleSset(db, sunset)
	QueryUpdateChar._id = db._id
	db._id = nil
	tempTb["$set"] = db
	tempTb["$unset"] = sunset
	LuaMongo.update(DB.db_char, QueryUpdateChar, tempTb)
	db._id = QueryUpdateChar._id
end

-------------------- humandb 初始化 start ----------------------
function createDefaultRole(account)
	local db = {
	    svrIndex = Config.SVR_INDEX,
		identity = nil,							-- 11位全局不重复的数字id
		account = account,						-- 帐号名
		name = nil,								-- 角色名
		changeNameCnt = nil,					-- 修改名字次数
		changeBase = nil,					    -- 修改基础信息次数
        birthDay = nil,                         -- 生日
        signature = nil,                        -- 个性签名
		lv = 1,									-- 等级
		exp = 0,
		zuanshi = 0,							-- 钻石
		jinbi = 0,								-- 金币
		createTime = nil,						-- 角色创建时间
		lastLoginTime = nil,					-- 上一次登录时间
		lastLogoutTime = nil,					-- 最近登出时间
		update_daily_time = nil,				-- 每天更新时间
		onlineTime = nil,						-- 在线时长
		onlineTimeDay = nil, 					-- 本日在线时长	
		onlineTimeDayReport = nil,	
		heroBag = {[0] = HeroDefine.HERO_BAG_CNT},		-- 英雄背包[index] ={id,lv等级,quality品阶}
		bag = {},								-- 道具背包 {itemID->itemCnt}
		fuwenBag = {},							-- 符文背包 [index] = {id, 属性, 技能}
        equipBag = {},                          -- 装备背包 [index] = {id, 属性, 技能}
		combatHero = {},						-- 出战英雄[type] = {[pos] = uuid}
		buyCapCnt = nil,						-- 购买背包容量次数
		heroBook = nil,                         -- 获得过的图鉴英雄[id]= true
		shop = nil,                             -- 商店购买物品次数记录 shop[shopType][itemID] = cnt
		
		guajiID = 0,						    -- 已通关关卡/挂机关卡
		battleID = 1,						    -- 战役即将战斗id
		battleHis = nil,						-- 战役历史记录（用于新手任务第五关特殊处理）
		battleRewards = nil, 					-- 征战奖励领取记录
		battleOut = nil,						-- 挂机收益{expTs1--经验开始产出时间戳,expTs2--经验产出结算时间戳,itemTs1--道具产出时间戳,itemTs2--道具产出结算时间戳,exp,jinbi,greenExp,items,itemsHalf}
		copy = nil,                             -- 活动副本 [1] ={cnt今日已挑战次数，buyCnt已购买次数} 
		dailyTask = nil,                        -- 每日任务
		bar = nil,                              -- [taskID] = {isLock是否锁定, star任务星级, nameID阿辛多, actionID委托, itemID, itemCnt, ts开始做任务时间戳, hero={index}上阵英雄, camp = {1,2}任务要求, job = {1}任务要求}
		zhuanpan = nil,                         -- [type] = {ts1[强制刷新时间戳],ts2[免费刷新时间戳],[1] = {id抽奖id, itemID奖品ID，itemCnt奖品数量,getCnt = nil抽到次数[该抽奖有次数限制才记录]
		tower = nil,                            -- 幻境之塔{当前关卡lv, 恢复时间ts, 当前体力值tili}
		drawCard = {jifen=0,list={[1]={},[2]={},[3]={},[4]={}}},--召唤法阵
		combatSpeed   = nil,                    -- 战斗速度
		jinbiExchange = nil,                    -- {[1][2][3]对应档位是否领取 ts刷新时间戳}
		vipLv = nil,							-- vip等级
		vipExp = nil,							-- vip经验（注意这个经验是累计的 升级不会清0）
		vipLibao = nil,							-- vip礼包标识
		vipYueka = nil, 						-- vip月卡额外奖励
		jjcBestRank = nil,						-- 个人竞技场最佳排名
		jjcDailyFight = nil,					-- 个人竞技场每日战斗次数
		chengjiu	= {},						-- 成就 
		onlineReward = nil,                     -- 在线奖励 {id, ts}
		combatQuick = {},						-- 快速战斗
		systemSet = nil,						-- 系统设置 位与操作  第4位  不展示vip  第5位  屏蔽私聊
		chatBan = nil,							-- 屏蔽聊天的玩家
		actMonthEndTime = nil,					-- 月度活动结束时间
		actMonthTask = nil, 					-- 月度活动进度
											    -- jifen hzz竞技积分 trial hzz皇家试炼积分 buyNum 破碎徽章购买  drunkery = {[id] = num} 酒馆活动  hecheng={[id] = num} 

		fundFlag = nil,							-- 钻石基金标志 nil未购买 1已购买未领完 2已购买已领完
        		
		friendHeart = 0,                        -- 友情值
        sendHeart = nil,                        -- 每日赠送红心好友列表{uuid->1}
        getHeartCnt  = nil,                     -- 每日领取红心次数
        sendHeartCnt = nil, 					-- 每日赠送红心次数
        friendBlack = nil, 						-- 黑名单
  
        buy = {},								-- 购买记录
		absAct = {},							-- 绝对时间活动数据
		loginGiveTime = nil,                    -- 登录赠送 (限时活动)  记录获得赠送时间
        signInCnt = nil,                        -- 登陆奖励次数
		signIn = nil,                           -- 登陆奖励状态，0 未登录，1，已登录未领取，2已登录已领取
		signInTime = nil,                       -- 登陆时间，用于判断是否是同一天登陆
		unionUuid = nil,                        -- 工会标志  如果玩家不属于任何工会，unionUuid为nil，否则unionUuid为工会唯一id                      
		ectypeCnt = nil,                        -- 公会副本每日通关次数
		ectypeLike = nil ,                      -- 公会副本点赞次数
		ectypLikeUuid = nil,                    -- 公会副本点赞人
		ectypHurt = nil,                        -- 公会副本每日伤害记录		
		combatVideos = nil, 					-- 战斗记录列表

        technology = nil,                       -- 公会科技信息
        ip = nil,                               -- 登录IP
        killEctype = nil,                       -- 参与击杀Boss等级   
        phpChanelID = nil,						-- 渠道导入id
		dailyShareTask = nil,                   -- 每日公共任务
        openServerGift = nil,                   -- 开服有礼

        mopupDoCnt = nil,                       -- 战役已扫荡次数
        mopupFreeCnt = nil,                     -- 战役已免费扫荡次数
		topupAcount = nil,                      -- 玩家充值总额
		topupAcountDaily = nil,					-- 玩家每日充值总额
		topupAccountMonth = nil,				-- 玩家每月充值总额
        firstCharge = nil,        	           	-- 超值首充 6元 100元
		godDailyTopup = nil,                    -- 成神之路每日礼包
		kingworld = nil,                        -- 国王君临       
       	superFund = nil, 						-- 超值基金 大小基金 [type] = {}
    
		sex = 1,										-- 性别 1男2女
    	head = RoleHeadLogic.DEFAULT_HEAD_MALE_ID,		-- 头像
    	headList = nil, 								-- 已激活头像列表（除默认赠送外）
        headFrame = RoleHeadLogic.DEFAULT_HEADFREAM_ID, -- 头像框
		headFrameList = nil,                  	-- 已激活头像框列表（除默认赠送外）
		body = nil,								-- 形象
		bodyList = nil,							-- 已激活形象
		chenghao = nil,							-- 称号
		chenghaoList = nil,						-- 已激活称号
		headHasNewFlag = nil,					-- 头像1/头像框2/形象4/称号8有新的flag
        animation = nil,                        -- 立绘
        animationList = nil,                    -- 已激活的立绘列表
		background = RoleHeadLogic.DEFAULT_BACKGROUND_ID,                       -- 背景
        backgroundList = nil,                   -- 已激活的背景列表
        throneTime = nil,                       -- 挑战失败记录时间

        banSay = nil,                           -- 被举报

        yellow = nil,                           -- 黄钻贵族
        blue = nil,                             -- 蓝钻贵族
        txHall = nil,                           -- 腾讯大厅
        qqZone = nil,                           -- QQ空间

		fuwenRefreshCnt = nil,                  -- 符文刷新次数
		helpCnt     = nil,                      -- 公会秘境助战次数        
		personMail   = nil,                      -- 私人郵件次數
		skinBag = {[0] = HeroDefine.HERO_SKIN_CNT},
		mailtips = {},                           -- 邮件提醒
		skinLog = {},							--皮肤获取记录
        lookGl = nil,                           -- 是否看过攻略
		tujianCP = nil,                         -- 图鉴CP
		
		personalrecord = nil,                    -- 炼狱个人记录
		
		middleFlag = nil,						-- 跨服游戏中
		middleOptions = nil,					-- 跨服操作事件
		
		leichongHaoli = nil, 					-- 累充好礼
		dailyLeiChong = nil, 					-- 每日累充 奖励发放 dailyLeiChong[1] = true
		battleExtraReward = nil, 				-- 征战关卡额外奖励
		plShare = nil, 							-- 微信小程序分享
		tuiSongLiBao = nil, 					-- 推送礼包
		heroResetCnt = nil, 					-- 英雄每日重置次数
		moshou = nil, 							-- 魔兽
        equipLogs = nil,                        -- 装备合成日志
        jjcGodWar = nil, 						-- 众神之战
        unionLive = nil,                        -- 公会活跃
		moShouPingFen = nil,                    -- 魔兽评分  
        unionDonate = nil,                      -- 公会捐献
        dailyBanggong = nil,                    -- 每日帮贡
        totalBanggong = nil,                    -- 总帮贡
        donateReward = nil,                     -- 公会捐献达标奖励
        combatBackup = nil,						-- 援军激活条件
        liLian = nil,	 						-- 历练
        billboard = nil, 						-- 排行榜-上榜时间
        billboardAim = nil, 					-- 排行榜-进度奖励
		lianyu = nil, 							-- 绝望深渊
        lianyuCache = nil, 						-- 绝望深渊战斗信息

        battleVideoUuid = nil,                  -- 战役挂机Uuid
        chatRead = nil,                         -- 聊天记录阅读到第几条
        dailyLibao = nil, 						-- 充值-每日礼包
        richangLibao = nil, 					-- 充值-每周/每月礼包
		tequanShop = nil, 						-- 充值-特权商店
		tequanMopup = nil, 						-- 扫荡特权 截止时间
		weekendFuli = nil, 						-- 周末福利
		unionWar = nil,                         -- 玩家 公会战 相关数据
		jjcLadder = nil, 						-- 天梯争霸 相关数据
		valleyTask = nil, 						-- 荣耀峡谷（龙族战场）目标

		jjcNewestRecord = nil,					-- 个人竞技场最新战斗记录时间
		jjcWorship = nil,					    -- 个人竞技场每日膜拜
		jjcBeWorship = nil,					    -- 个人竞技场总被膜拜次数

        relationKey = nil,                      -- 推广码
        relationBind= {},                       -- 推广关系
        relationId = nil,                       -- 推广人
        relationRew = {},                       -- 奖励领取状态

        warReport = {},                         -- 战报收藏列表
		warAdmire = nil,                        -- 战报点赞
		drill  = nil,                           -- 勇者试炼

        welfareGift = {},                       -- 超值礼包

        redBagCnt = nil,                        -- 公会红包次数
        monthCard = nil,						-- 贵族月卡，王者月卡
        limitBuy = nil,							-- 限时抢购
        leijiChongzhi = nil,					-- 累计充值
        giftPack = nil,                         -- 成长礼包

        heroRise = nil,                         -- 英雄崛起
		leaveUnionLimit = nil,                  -- 离开公会后，加入或创建公会时间限制
		roleDot  = nil,                         -- 红点
		chongJi  = nil,                         -- 创角冲级活动
		cdkFix = nil, 							-- 固定兑换码
        roleSys = nil,                          -- 系统开放标识
        roleSysOpen = nil,                      -- 系统点击标识
		
		xingYaoGongMing = nil, 					-- 星耀之门-星耀共鸣

        guide = nil,    -- 指引
        lvGuide = nil,  -- 等级指引

        sendPfEmail = nil, --开服邮件
		
		limitMangHe = nil,    				    -- 开服  -限时幸运盲盒

        fpsTb = nil,                            -- fps信息
		
		systemSound = nil,                       -- 系统设置

        relic = {},                            -- 圣器
		
		-- 注意 以后再加字段如初始化为非nil 要在下面的newAddDBData同步加，否则老号会报错。
	}
	db.createTime = os.time()

	LuaMongo.insert(DB.db_char, db)	
	return db
end

local newAddDBData = {}
local roleDBchanged
local function handleNew(orgDB, newTable)
	for k, v in pairs(newTable) do
		if not orgDB[k] then
			orgDB[k] = v
			roleDBchanged = true
		elseif type(v) == "table" then
			handleNew(orgDB[k],v)
		end
	end
end

function roleDBInit()
    _G.collectgarbage("step", 1000000)

    LuaMongo.find(DB.db_char)
    local list = {}
    local all = 0
    while true do
        local data = {}
        if not LuaMongo.next(data) then
        	break
        end
        all = all + 1
        roleDBchanged = nil
        handleNew(data, newAddDBData)
        if roleDBchanged then
        	list[#list + 1] = data._id
        end
    end
    print(#list, "/", all)
    
    _G.collectgarbage("step", 1000000)
    
    local query = {}
    for _, v in ipairs(list) do
        query._id = v
        LuaMongo.find(DB.db_char, query)
        local data = {}
        if not LuaMongo.next(data) then
        	assert()
        end
        roleDBchanged = nil
        handleNew(data, newAddDBData)
        if not roleDBchanged then
        	assert()
        end
        LuaMongo.update(DB.db_char, query, data)
    end
end
-------------------- humandb 初始化 end ----------------------
